#pragma once
#include "gtest/gtest.h"
#include "Utility/FileSystem/SGFileSystem.h"
#include "DataStructure/Common/Status.h"
#include "SGFem/Task/Common/DynamicLoad.h"
#include "SGFem/Task/Kernel/MModel.h"
#include "SGFem/Pre/Assembly/Assembly.h"

#include "../LoadCalculator.h"

extern std::shared_ptr<DBServiceFactory> DB_SERVICEFACTORY;

using SG::DataStructure::FEM::TLOAD1Data;
using SG::Import::SGImporter;

class TLOAD1UseLSEQTest : public ::testing::Test
{
public:
    static void SetUpTestSuite ()
    {
        const auto fileName = SG::Utility::FileSystem::getTestDataPath("SGFem/Task/DynaLoad/") + "lseq-multiple-sid-exciteid-differ.bdf";
        DB_SERVICEFACTORY->ClearDatabase ();
        SGImporter import (DB_SERVICEFACTORY);
        import.Import (fileName);

        Kernel::MModel modal (SOLType::SOL_SEDTRAN, DB_SERVICEFACTORY);

        // 单元计算
        modal.Initialize ({ 1 });
        modal.CalcMatrixEquation (1);
    }

    // 工况控制段，指定的 loadsetid
    Id  caseLoadSetId = 10;
};


TEST_F (TLOAD1UseLSEQTest, LSEQRefGrav)
{
    TLOAD1Data tload1Grv;
    tload1Grv.m_sId = 5;
    tload1Grv.m_DAREA = 4;
    tload1Grv.m_F = -3.12;

    // 这个函数其实已经在 modal.Initialize 中被调用
    // 测试, 正确找到重力载荷 sid 100
    auto loadSidSet = getStaticLoadId (tload1Grv, DB_SERVICEFACTORY, caseLoadSetId);
    ASSERT_EQ (loadSidSet[0], 100);

    // 正确计算载荷的空间分布
    TLoad1Calc loadCalc (tload1Grv, caseLoadSetId, 1.0);    
    loadCalc.computeA (DB_SERVICEFACTORY, 1);
    const auto&  ATest = loadCalc.getStaticForce ();

    /**
     * @brief   模型中 10个节点，需要排除 3个 spc 节点， 一个 mpc从节点
     * 
     * fTest 的维度为 （10-3-1）*6 = 36
     * 
     */
    Real ATarget[36] = {-0.000117,  0.012168, -0.01287, 0.0, 0.0, 0.0,
                       -0.0000585, 0.006084, -0.006435,0.0, 0.0, 0.0,
                       -0.000117,  0.012168, -0.01287, 0.0, 0.0, 0.0,
                       -0.0000585, 0.006084, -0.006435,0.0, 0.0, 0.0,
                       -0.000117,  0.012168, -0.01287, 0.0, 0.0, 0.0,
                       -0.000234,  0.024336, -0.02574, 0.0, 0.0, 0.0
    };

    for (int posi{0}; posi < 36; ++posi)
    {
        ASSERT_NEAR(ATarget[posi], ATest(posi), TOLERANCE);
    }

    // todo 验证插值功能
    Real t{0.1};
    auto fTest = loadCalc.Interplate (DB_SERVICEFACTORY, t);
}

TEST_F (TLOAD1UseLSEQTest, LSEQRefPLoad4)
{
    TLOAD1Data tload1Pload4;

    tload1Pload4.m_sId = 5;
    tload1Pload4.m_DAREA = 12;
    tload1Pload4.m_TID = 6;

    // 测试，正确找到pload4 的 sid 101
    auto loadSidSet = getStaticLoadId (tload1Pload4, DB_SERVICEFACTORY, caseLoadSetId);
    ASSERT_EQ (loadSidSet[0], 101);
    
    // 正确计算载荷的空间分布
    TLoad1Calc loadCalc (tload1Pload4, caseLoadSetId, 1.0);    
    loadCalc.computeA (DB_SERVICEFACTORY, 1);
    const auto&  ATest = loadCalc.getStaticForce ();

    /** Target data
     * @brief   模型中 10个节点，需要排除 3个 spc 节点（11       4      10）， 一个 mpc从节点
     * 
     * fTest 的维度为 （10-3-1）*6 = 36
     * 
     * pload4 作用到 12号单元 （7号节点【自由度12 - 17】， 8号节点【自由度18 - 23】，9号节点【自由度24 - 29】，12号节点【自由度30 - 35】）
     */
    std::vector<Real> ATarget (36, 0.0);
    ATarget[14] = 0.625;
    ATarget[20] = 0.625;
    ATarget[26] = 0.625;
    ATarget[32] = 0.625;

    for (int posi{0}; posi < 36; ++posi)
    {
        ASSERT_NEAR(ATarget[posi], ATest(posi), TOLERANCE);
    }

    // 验证插值功能
    // 此插值表在 【0.0， 10.0】 内线性插值到 [0.0, 1.0], 因此t =0.1s 插值系数为 1/100.0
    Real t{0.1};
    auto fTest = loadCalc.Interplate (DB_SERVICEFACTORY, t);
    // std::cout << fTest;
    for (int posi{0}; posi < 36; ++posi)
    {
        ASSERT_NEAR(ATarget[posi]*0.01, fTest(posi), TOLERANCE);
    }
}


// 测试DAREA计算能否正确处理MPC SPC荷载
TEST (TLOAD1UseDareaTest, DAREADofIsMPCMSet)
{
    const auto fileName = SG::Utility::FileSystem::getTestDataPath("SGFem/Task/DynaLoad/") 
                          + "EleTes-DirecTrans-tload1_exciteid-darea_rbe3.bdf";
    
    DB_SERVICEFACTORY->ClearDatabase();

    // 导入BDF模型
    SGImporter import(DB_SERVICEFACTORY);
    
    ASSERT_TRUE( SG::DataStructure::Common::Status::STATUS_Success == import.Import (fileName) ) << "测试BDF文件导入失败";

    Kernel::MModel modal (SOLType::SOL_SEDTRAN, DB_SERVICEFACTORY);
    
    // 单元计算
    modal.Initialize ({ 1 });
    modal.CalcMatrixEquation (1);
    // modal.ComputeFValue (1); 
    
    // 计算荷载
    SG::DataStructure::FEM::DAREAData DareALoad1;
    DareALoad1.m_sId = 4;
    DareALoad1.m_P   = 28;
    DareALoad1.m_C   = 3;
    DareALoad1.m_A   = 50.0;
    SG::DataStructure::FEM::DAREAData DareALoad2;
    DareALoad2.m_sId = 4;
    DareALoad2.m_P   = 28;
    DareALoad2.m_C   = 4;
    DareALoad2.m_A   = 4000.0;
    std::vector<SG::DataStructure::FEM::DAREAData> DAREAList = {DareALoad1, DareALoad2};
    
    SG::Algebra::Vec_t DAREATest;
    LoadCalculator::calcDAREAForce (DAREAList, DAREATest);
    
    // 开始测试验证
    // nastran计算结果的PCH文件中截取部分有：
    /* 
    *                     20               3 2.561770320E+01
    *                     20               4 5.405779056E+02
    *                     20               5 5.586991979E+01
    * 
    *                     23               3-8.951036534E+00
    *                     23               4 5.405779056E+02
    *                     23               5 5.586991979E+01
    * 
    *                     27               3 6.704389034E+00
    *                     27               4 5.405779056E+02
    *                     27               5 5.586991979E+01
    */
    ASSERT_NEAR(DAREATest[ 62 ], 2.561770320E+01, TOLERANCE);
    ASSERT_NEAR(DAREATest[ 63 ], 5.405779056E+02, TOLERANCE);
    ASSERT_NEAR(DAREATest[ 64 ], 5.586991979E+01, TOLERANCE);
    ASSERT_NEAR(DAREATest[ 80 ], -8.951036534E+00,TOLERANCE);
    ASSERT_NEAR(DAREATest[ 81 ], 5.405779056E+02, TOLERANCE);
    ASSERT_NEAR(DAREATest[ 82 ], 5.586991979E+01, TOLERANCE);
    ASSERT_NEAR(DAREATest[ 104], 6.704389034E+00, TOLERANCE);
    ASSERT_NEAR(DAREATest[ 105], 5.405779056E+02, TOLERANCE);
    ASSERT_NEAR(DAREATest[ 106], 5.586991979E+01, TOLERANCE);
}